package cn.yeziji.forum.dao.intf;

import cn.org.atool.fluent.mybatis.base.IBaseDao;
import cn.yeziji.forum.bo.chatroom.ChatPrivateMsgBO;
import cn.yeziji.forum.bo.user.UserRegisterBO;
import cn.yeziji.forum.common.ForumPageResult;
import cn.yeziji.forum.common.key.UserCacheKey;
import cn.yeziji.forum.dto.user.EmailDTO;
import cn.yeziji.forum.dto.user.UserFocusOrFansListPagingDTO;
import cn.yeziji.forum.dto.user.UserRegisterDTO;
import cn.yeziji.forum.dto.user.UserUpdateDTO;
import cn.yeziji.forum.entity.ForumUserEntity;
import cn.yeziji.forum.vo.user.UserMsgVO;
import cn.yeziji.forum.vo.user.UserUpdateVO;
import com.alibaba.fastjson.JSONObject;

import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 用户操作逻辑层
 *
 * @author gzkemays
 * @since 2021/12/21 15:54
 */
public interface ForumUserDao extends IBaseDao<ForumUserEntity> {
  Integer USERNAME_MIN_LENGTH = 3;
  Integer USERNAME_MAX_LENGTH = 10;
  Integer PASSWORD_MIN_LENGTH = 5;
  long TIMESTAMP_FLUCTUATIONS = 30 * 1000 * 60;

  /**
   * 注册 email
   *
   * @param email 电子邮箱
   */
  void registerSendEmail(EmailDTO email);
  /**
   * 根据用户名查找用户
   *
   * @param username 用户名
   * @return 用户信息
   */
  ForumUserEntity selectUserByUserName(String username);
  /**
   * 根据用户昵称查找用户
   *
   * @param nickname 用户名
   * @return 用户信息
   */
  ForumUserEntity selectUserByNickName(String nickname);

  /**
   * 查询用户关注列表
   *
   * <p>该接口不能同时获取关注和粉丝列表，只能单独获取
   *
   * @param pagingDTO 获取粉丝或关注信息列表，只能其中之一为 true
   * @return 用户信息列表
   */
  ForumPageResult<UserMsgVO> getFocusOrFansUserMsg(UserFocusOrFansListPagingDTO pagingDTO);
  /**
   * 查询用户关注列表
   *
   * <p>该接口同时获取关注和粉丝列表，它与原来的 {@link #getFocusAndFansUserMsg()} 不同在于，它的缓存是动态的。受 userId 和 nickname
   * 的变化影响
   *
   * @param pagingDTO 获取粉丝和关注信息列表
   * @return 用户信息列表
   */
  ForumPageResult<UserMsgVO> getFocusAndFansUserMsg(UserFocusOrFansListPagingDTO pagingDTO);

  /**
   * 获取2者用户的信息
   *
   * @param to 发送用户
   * @param from 接收用户
   * @return 私聊用户信息
   */
  ChatPrivateMsgBO getByToAndFromUserMsg(String to, String from);

  /**
   * 根据用户昵称获取用户信息，这里包括当前请求用户是否关注过等操作……
   *
   * @param nickname 用户昵称
   * @return 用户信息
   */
  UserMsgVO getUserMsg(String nickname);

  /**
   * 根据多个 nickname 获取其用户信息
   *
   * @param nickname nickname 列表
   * @return 用户信息列表
   */
  List<UserMsgVO> getUserMsgList(List<String> nickname);

  /**
   * 获取关注用户列表
   *
   * @return 用户列表
   * @deprecated 使用 {@link #getFocusAndFansUserMsg(UserFocusOrFansListPagingDTO)} 根据条件来获取粉丝和关注对象
   */
  List<UserMsgVO> getFocusAndFansUserMsg();

  /**
   * 根据用户 id 获取他的粉丝数据
   *
   * @param userId 用户 id
   * @return 粉丝信息列表
   */
  List<ForumUserEntity> getFansUserMsgById(Integer userId);

  /**
   * 注册用户
   *
   * @param entity 用户实体类
   * @return 返回新增id
   * @deprecated 摒弃登录注册一体化的方式，将登录与注册分开便于邮箱与字段校验。
   * @see #register(UserRegisterDTO) 注册
   */
  ForumUserEntity registerUser(UserRegisterBO entity);

  /**
   * 登录
   *
   * @param username 用户名
   * @param password 密码
   * @return 用户信息
   */
  ForumUserEntity login(String username, String password);

  /**
   * 用户注册
   *
   * @param dto 注册对象
   */
  void register(UserRegisterDTO dto);

  /**
   * 更新用户信息
   *
   * <ul>
   *   <li>关注用户时，发送 focus: nickname
   * </ul>
   *
   * @param dto 用户实体类
   * @return java.lang.Integer
   */
  UserUpdateVO update(UserUpdateDTO dto);

  /** 获取服务器用户数量 */
  int getUserCount();

  class UserDaoCacheKey {
    int id;
    String username;

    public UserDaoCacheKey id(Integer id) {
      this.id = id == null ? 0 : id;
      return this;
    }

    public UserDaoCacheKey username(String username) {
      this.username = username == null ? "" : username;
      return this;
    }

    public static String getNameEntityCacheKey(String nickname) {
      return UserCacheKey.USER_ENTITY_BY_NICKNAME_CACHE + nickname;
    }

    public static String get0NameEntityCacheKey(String username) {
      return UserCacheKey.USER_ENTITY_BY_USERNAME_CACHE + username;
    }

    public static UserDaoCacheKey builder() {
      return new UserDaoCacheKey();
    }

    public String generateKey() {
      return builder().id(id).username(username).build();
    }

    public String build() {
      return id + "_" + username;
    }
  }
}
